﻿using System.Collections.Generic;
using EnetaMvc.Core.Domain.Forums;
using EnetaMvc.Core.Repositories;
using EnetaMvc.Infrastructure;
using NHibernate;
using NHibernate.Criterion;

namespace EnetaMvc.Data.NHibernate.Repositories
{
    public class ForumRepository : BaseRepository, IForumRepository
    {
        private readonly ISession _session;

        public ForumRepository(IMapperSession session) : base(((NHSession)session).GetCurrentSession())
        {
            _session = ((NHSession)session).GetCurrentSession();
        }

        public IList<ForumCategory> ListForumCategories()
        {
            return _session.CreateCriteria<ForumCategory>().List<ForumCategory>();
        }

        public ForumCategory GetForumCategoryById(long id)
        {
            return _session.Get<ForumCategory>(id);
        }

        public void SaveForumCategory(ForumCategory category)
        {
            SaveInTransaction(category);
        }


        public long GetTopicCountInForum(long forumId)
        {
            var criteria = _session.CreateCriteria<ForumPost>();
                criteria.Add(Expression.IsNull("Parent"));
                criteria.CreateCriteria("Forum").Add(Expression.Eq("Id", forumId));
                criteria.SetProjection(Projections.Count("Id"));
            
            return criteria.UniqueResult<int>();
        }

        public long GetPostCountInForum(long forumId)
        {
            var criteria = _session.CreateCriteria<ForumPost>();
                criteria.CreateCriteria("Forum").Add(Expression.Eq("Id", forumId));
                criteria.SetProjection(Projections.Count("Id"));

            return criteria.UniqueResult<int>();
        }

        public ForumPost GetLastPostForForum(long id)
        {
            var criteria = _session.CreateCriteria<ForumPost>();
            criteria.CreateCriteria("Forum").Add(Expression.Eq("Id", id));
            criteria.SetMaxResults(1);
            criteria.AddOrder(Order.Desc("Id"));

            return criteria.UniqueResult<ForumPost>();
        }


        public Forum GetForumById(long id)
        {
            return _session.Get<Forum>(id);
        }


        public PagedResult<ForumPost> ListPostsForForum(long id, int page, int pageSize)
        {
            var criteria = _session.CreateCriteria<ForumPost>();
            criteria.Add(Expression.IsNull("Parent"));
            criteria.CreateCriteria("Forum").Add(Expression.Eq("Id", id));
            criteria.AddOrder(Order.Desc("Id"));

            return GetPagedResultForQuery<ForumPost>(criteria, page, pageSize);
        }

        public ForumPost GetForumPostById(long id)
        {
            return _session.Get<ForumPost>(id);
        }

        public Forum GetForumByPostId(long id)
        {
            var post = GetForumPostById(id);
            if (post == null)
                return null;

            return post.Forum;
        }

        public void SaveForumPost(ForumPost post)
        {
            if (post == null)
                return;

            SaveInTransaction(post);
        }

        public IList<ForumPost> ListLastTopicsForRss()
        {
            var criteria = _session.CreateCriteria<ForumPost>();
            criteria.Add(Expression.IsNull("Parent"));
            criteria.AddOrder(Order.Desc("Created"));
            criteria.SetMaxResults(10);

            return criteria.List<ForumPost>();
        }

        public IList<ForumPost> ListLastRepliesForRss()
        {
            var criteria = _session.CreateCriteria<ForumPost>();
            criteria.Add(Expression.IsNotNull("Parent"));
            criteria.AddOrder(Order.Desc("Created"));
            criteria.SetMaxResults(10);

            return criteria.List<ForumPost>();
        }

        public IList<ForumPost> ListLastTopicsForCategoryRss(long categoryId)
        {
            var criteria = _session.CreateCriteria<ForumPost>();
            criteria.Add(Expression.IsNull("Parent"));
            criteria.AddOrder(Order.Desc("Created"));
            criteria.SetMaxResults(10);

            criteria.CreateCriteria("Forum").CreateCriteria("Category").Add(Expression.Eq("Id", categoryId));

            return criteria.List<ForumPost>();
        }


        public IList<ForumPost> ListPostsOverForumsExclusive(long[] excludeForumIds, int resultCount)
        {
            var criteria = _session.CreateCriteria<ForumPost>();
            criteria.Add(Expression.IsNull("Parent"));
            criteria.AddOrder(Order.Desc("Created"));
            criteria.SetMaxResults(resultCount);

            if (excludeForumIds != null)
            {
                var categoryCriteria = criteria.CreateCriteria("Forum");

                foreach (var forumId in excludeForumIds)
                    categoryCriteria.Add(Expression.Not(Expression.Eq("Id", forumId)));
            }

            return criteria.List<ForumPost>();
        }


        public void DeleteForumCategory(ForumCategory category)
        {
            if (category == null)
                return;

            DeleteInTransaction(category);
        }


        public void DeleteForum(Forum forum)
        {
            if (forum == null)
                return;

            DeleteInTransaction(forum);
        }


        public void SaveForum(Forum forum)
        {
            if (forum == null)
                return;

            SaveInTransaction(forum);
        }

        public void DeleteForumPost(ForumPost post)
        {
            if (post == null)
                return;

            DeleteInTransaction(post);
        }
    }
}
